package ru.spbau.design.snmp.android.viewer.model;

import java.util.Arrays;

public final class IPAddress implements Cloneable {
	
	public IPAddress(int[] address, int[] mask) throws ModelException {
		validateByteIp(address);
		validateByteIp(mask);
		this.address = address;
		this.mask = mask;
	}
	
	public IPAddress(String address) throws ModelException {
		validateStringIp(address);
		this.address = parseIp(address);
		this.mask = null;
	}
	
	public IPAddress(String address, String mask) throws ModelException {
		validateStringIp(address);
		validateStringIp(mask);
		this.address = parseIp(address);
		this.mask = parseIp(mask);
	}
	
	public IPAddress(IPAddress src) {
		this.address = src.address;
		this.mask = src.mask;
	}
	
	public int[] getAddress() {
		return address;
	}
	
	public String getAddressStr() {
		return ipToString(address);
	}
	
	public int[] getMask() {
		return mask;
	}
	
	public String getMaskStr() {
		return ipToString(mask);
	}
	
	@Override
	protected Object clone() {
		return new IPAddress(this);
	}	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(address);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		IPAddress other = (IPAddress) obj;
		if (!Arrays.equals(address, other.address))
			return false;
		return true;
	}

	private static void validateStringIp(String address) throws ModelException {
		String[] nums = address.split("\\.");
		if (nums.length != 4) {
			throw new ModelException("Invalid string ip: hasn't 4 numbers");
		}
		int[] byteIp = parseIp(address);		
		validateByteIp(byteIp);
	}
	
	private static Boolean validateByteIp(int[] address) throws ModelException {
		if (address.length != 4) {
			throw new ModelException("Invalid byte IP: hasn't 4 numbers");
		}
		for(int i = 0; i != 4; ++i) {
			if (address[i] < 0 || address[i] > 255) {
				throw new ModelException("Invalid byte IP: has number < 0 or > 255");
			}
		}
		return true;
	}
	
	private static int[] parseIp(String address) {
		int[] res = new int[4];
		String[] nums = address.split("\\.");
		res[0] =  Integer.parseInt(nums[0]);
		res[1] =  Integer.parseInt(nums[1]);
		res[2] =  Integer.parseInt(nums[2]);
		res[3] =  Integer.parseInt(nums[3]);
		return res;
	}
	
	private static String ipToString(int[] address) {
		StringBuilder b = new StringBuilder();
		b.append(Integer.toString(address[0]));
		b.append('.');
		b.append(Integer.toString(address[1]));
		b.append('.');
		b.append(Integer.toString(address[2]));
		b.append('.');
		b.append(Integer.toString(address[3]));
		return b.toString();
	}
	
	private final int[] address;
	private final int[] mask;
}